package ludichat.cobbreeding

import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.mojang.logging.LogUtils.getLogger
import dev.architectury.registry.ReloadListenerRegistry
import dev.architectury.registry.registries.DeferredRegister
import dev.architectury.registry.registries.RegistrySupplier
import kotlinx.serialization.ExperimentalSerializationApi
import ludichat.cobbreeding.components.CobbreedingComponents
import ludichat.cobbreeding.net.IncubatorAbilityPacket
import ludichat.cobbreeding.net.IncubatorAbilityPacketHandler
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.packs.PackType
import net.minecraft.server.packs.resources.ResourceManagerReloadListener
import net.minecraft.world.item.Item
import org.slf4j.Logger
import java.io.File
import java.io.FileReader
import java.io.FileWriter

object Cobbreeding {
    const val MOD_ID = "cobbreeding"

    private const val CONFIG_PATH = "config/cobbreeding/main.json"

    internal val ITEMS: DeferredRegister<Item> = DeferredRegister.create(MOD_ID, Registries.ITEM)

    @JvmField
    val LOGGER: Logger = getLogger()

    @JvmField
    val EGG_ITEMS: HashMap<String, RegistrySupplier<PokemonEgg>> = HashMap.newHashMap(326)

    // Cache per players indicating if their egg should hatch faster
    val INCUBATOR_ABILITIES_REGISTRY: IncubatorAbilitiesRegistry = IncubatorAbilitiesRegistry()
    val INCUBATOR_PACKET_INFO: PacketRegisterInfo<IncubatorAbilityPacket> = PacketRegisterInfo(IncubatorAbilityPacket.ID, IncubatorAbilityPacket::decode, IncubatorAbilityPacketHandler)

    lateinit var config: Config

    fun init() {
        LOGGER.info("Registering items")

        registerEggs()
        ITEMS.register()

        LOGGER.info("Registering data components")
        CobbreedingComponents.COMPONENT_TYPES.register()

//        CommandRegistrationEvent.EVENT.register { dispatcher, _, _ ->
//            dispatcher.register(LiteralArgumentBuilder.literal(""))
//        }

        ReloadListenerRegistry.register(PackType.SERVER_DATA, ResourceManagerReloadListener {
            LOGGER.info("Loading configuration")
            loadConfig()
        }, ResourceLocation.fromNamespaceAndPath(MOD_ID, "cobbreeding-data"))

        // Adding and removing players from the incubators cache
        PlatformEvents.SERVER_PLAYER_LOGIN.subscribe {
            INCUBATOR_ABILITIES_REGISTRY.add(it.player)
        }
        PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
            INCUBATOR_ABILITIES_REGISTRY.remove(it.player)
        }


    }

    private fun registerEggs()
    {
        val types = listOf("bug", "dark", "dragon", "electric", "fairy", "fighting", "fire", "flying", "ghost",
                "grass", "ground", "ice", "normal", "poison", "psychic", "rock", "steel", "water")

        EGG_ITEMS["pokemon_egg"] = ITEMS.register("pokemon_egg") {PokemonEgg(Item.Properties().stacksTo(1))}
        EGG_ITEMS["manaphy_egg"] = ITEMS.register("manaphy_egg") {PokemonEgg(Item.Properties().stacksTo(1))}

        // 注册所有类型蛋和类型组合蛋
        for (type1 in types)
        {
            EGG_ITEMS["${type1}_pokemon_egg"] = ITEMS.register("${type1}_pokemon_egg") {PokemonEgg(Item.Properties().stacksTo(1))}
            for (type2 in types)
            {
                if (type1 != type2)
                    EGG_ITEMS["${type1}_${type2}_pokemon_egg"] = ITEMS.register("${type1}_${type2}_pokemon_egg") {PokemonEgg(Item.Properties().stacksTo(1))}
            }
        }
    }

    @OptIn(ExperimentalSerializationApi::class)
    fun loadConfig() {
        val configFile = File(CONFIG_PATH)
        configFile.parentFile.mkdirs()

        if (configFile.exists()) {
            try {
                val fileReader = FileReader(configFile)
                config = Config.GSON.fromJson(fileReader, Config::class.java)
                fileReader.close()
            } catch (e: Exception) {
                LOGGER.error("Config error: ${e.message}")
                LOGGER.warn("Config has been reset.")
                config = Config()
            }
        } else {
            config = Config()
        }

        saveConfig()
    }

    @OptIn(ExperimentalSerializationApi::class)
    fun saveConfig() {
        try {
            val configFile = File(CONFIG_PATH)
            val fileWriter = FileWriter(configFile)
            // Put the config to json then flush the writer to commence writing.
            Config.GSON.toJson(config, fileWriter)
            fileWriter.flush()
            fileWriter.close()
        } catch (exception: Exception) {
            LOGGER.error("Failed to save the config! Please consult the following stack trace:")
            exception.printStackTrace()
        }

    }
}
